package com.atguigu.spzx.user.service.Impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.spyx.model.common.ResultCodeEnum;
import com.atguigu.spyx.model.exception.SpzxException;
import com.atguigu.spzx.user.config.SmsConst;
import com.atguigu.spzx.user.config.SmsProperties;
import com.atguigu.spzx.user.mapper.UserInfoMapper;
import com.atguigu.spzx.user.service.SmsService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import util.HttpUtils;
import util.RegexValidateUtils;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author LT
 * @create 2023-11-19-22:39
 */
@Service
@EnableConfigurationProperties(SmsProperties.class)
public class SmsServiceImpl implements SmsService {
    @Resource
    UserInfoMapper userInfoMapper;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public void sendMsg(String phone, Integer type) {
        //1、参数校验：
        boolean b = RegexValidateUtils.checkCellphone(phone);
        if(!b){
            //手机号格式错误
            throw new SpzxException(ResultCodeEnum.MOBILE_ERROR , null);
        }
        //2、判断发送哪种类型的短信，调用对应的业务方法处理
        if(type==null){
            //默认没有type发送注册短信
            sendRegistMsg(phone);
        }


    }

    private void sendRegistMsg(String phone) {
        //2.1 判断手机号是否被占用
        Integer count = userInfoMapper.findCountByPhone(phone);
        if(count>0){
            throw new SpzxException(ResultCodeEnum.MOBILE_EXIST_ERROR , null);
        }

        //2.2 获取验证码次数/频次校验
        String limitKey = "user:sms:limit:" + phone; //2分钟不能重复获取的key
        String timesKey = "user:sms:times:" + phone;//一天只能获取5条短信的key

        if(stringRedisTemplate.hasKey(limitKey)){
            throw new SpzxException(ResultCodeEnum.MSG_LIMIT_ERROR , null);
        }
        String timesStr = stringRedisTemplate.opsForValue().get(timesKey);
        if(!StringUtils.isEmpty(timesStr) && Integer.parseInt(timesStr)>=5){
            throw new SpzxException(ResultCodeEnum.MSG_TIMES_ERROR , null);
        }


        //2.3 发送验证码
        String host = SmsProperties.HOST;
        String path = SmsProperties.PATH;
        String method = SmsProperties.METHOD;
        String appcode = SmsProperties.APPCODE;
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
        //短信模板：
        bodys.put("template_id", SmsProperties.TEMPLATE_ID);
        //短信模板需要的参数：
        String code = RandomUtil.randomNumbers(4);
        bodys.put("content", "code:"+code+",expire_at:15");
        //手机号：
        bodys.put("phone_number", phone);

        System.out.println(code);

        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            //解析响应报文：判断请求成功还是失败
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode==400){
//                throw new SpzxException(Re,null);
                System.out.println("请求参数错误");
                throw new SpzxException(ResultCodeEnum.ERROR , null);
            }else if(statusCode==403){
                System.out.println("触发限发机制（10分钟发3条短信）/ 套餐余额用完");
                throw new SpzxException(ResultCodeEnum.ERROR , null);
            }else if(statusCode== 500 ){
                System.out.println("短信平台异常");
                throw new SpzxException(ResultCodeEnum.ERROR , null);
            }else if(statusCode==200){
                //短信发送响应成功
                //获取响应体中的响应的json字符串
                String result = EntityUtils.toString(response.getEntity(), Charset.defaultCharset());
                //将json转为Map
                Map<String,String> map = JSON.parseObject(result, Map.class);
                String status = map.get("status");
                if("ok".equalsIgnoreCase(status)){
                    //短信发送成功
                    System.out.println(result);
                    //2.4 缓存验证码到redis
                    stringRedisTemplate.opsForValue().set(SmsConst.SMS_CODE_PREFIX+phone , code ,
                            15, TimeUnit.MINUTES);
                    //2.5 更新验证码获取的频次
                    // 2分钟内不能重复获取 ， 1天只能发送5次

                    stringRedisTemplate.opsForValue().set(limitKey, "1" ,
                            2,TimeUnit.MINUTES);
                    //发送成功：每天获取验证码次数上+1 :
                    Long increment = stringRedisTemplate.opsForValue().increment(timesKey);
                    if(increment.longValue()==1L){
                        //第一次获取验证码成功 设置次数key的过期时间为1天
                        stringRedisTemplate.expire(timesKey, 1,TimeUnit.DAYS);
                    }

                }else{
                    //短信发送失败
                    System.out.println("短信发送失败："+map.get("reason"));
                    throw new SpzxException(ResultCodeEnum.ERROR , null);
                }
            }else{
                System.out.println("未知错误");
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new SpzxException(ResultCodeEnum.MSG_SEND_ERROR , e);
        }
    }
}
